// 路由：在页面中设置视图来存储多个组件，当页面路径变化时，视图根据路径切换到对应的组件

// 导入相关路由配置的函数
import { createRouter, createWebHistory, createWebHashHistory, RouteRecordRaw } from "vue-router";

// 使用 meta 定义元信息时，需要在 vue-router 的声明文件中定义 RouteMeta 接口
declare module 'vue-router'{
  interface RouteMeta{
    title:string
  }
}

// 路由对象数组设置，类型为 RouteRecordRaw 路由对象组成的数组
const routes: Array<RouteRecordRaw> = [
  // 路由对象具有若干个配置属性
  {
    // alias: Array<string> 为该路由设置额外的路径别名，即额外的跳转依据
    alias: ['/login'],
    // meta: {} 对象中包含自定的信息
    meta: {
      title: '登录页面'
    },
    // path: string 为路由跳转的依据
    path: '/',
    // name: string 为路由跳转依据
    name: 'Login',
    // component: () => import(pathString)
    // componengts: {name: component}
    // 为路由跳转页面中的视图显示的组件
    // 采用 componengts 时，为命名视图，即在路由跳转时，页面中存在多个视图显示不同的对应组件
    components: {
      A: () => import('../components/A/Login.vue'),
      B: () => import('../components/B/Login.vue')
    }
  },
  {
    meta: {
      title: '首页'
    },
    path: '/index',
    name: 'Index',
    components: {
      A: () => import('../components/A/Index.vue'),
      B: () => import('../components/B/Index.vue')
    },
    // redirect: { path:string } 在父路由上可以设置重定向，即访问到该页面时，重定向到目标页面
    // 重定向实质也是一次跳转，可以进行传参等操作
    redirect: {
      path:'/index/inner1'
    },
    // children:Array<RouteRecordRaw> 设置嵌套路由，且当为嵌套路由时，可以在父路由上设置重定向
    children: [{
      meta: {
        title: '内部页面1'
      },
      name:'Inner1',
      // 在路径设置时，可以采用 :key 的形式设置路径参数
      path: '/index/inner1',
      components: {
        A: () => import('../components/A/Inner1.vue'),
        B: () => import('../components/B/Inner1.vue')
      }
    },
    {
      meta: {
        title: '内部页面2'
      },
      name:'Inner2',
      path: '/index/inner2',
      components: {
        A: () => import('../components/A/Inner2.vue'),
        B: () => import('../components/B/Inner2.vue')
      }
    },]
  },
  {
    meta: {
      title: '公开页面'
    },
    path: '/public',
    name: 'Public',
    components: {
      A: () => import('../components/A/Public.vue'),
      B: () => import('../components/B/Public.vue')
    }
  },
]
// 调用 createRouter 创建 router 实例
// 参数为配置对象
const router = createRouter({
  // history 配置属性，指定 router 的模式
  // 基于 h5 history 模式，调用 createWebHistory()
  // 基于 loaction.hash 模式，调用 createWebHashHistory()
  history: createWebHistory(),
  // 滚轮行为：即重新跳转回某一页面时，滚轮应停留的位置
  // 采用函数形式定义，返回值为对象，对象具有 top 属性，指定滚轮位置
  // 函数参数可以访问到 to from ，表示路由跳转的目标和原 Route 对象
  // 当组件存在滚动条时，当离开该页面时，会记录滚动条位置到 savedPosition 中
  scrollBehavior: (to, from, savedPosition) => {
    // savedPostion 仅在具有滚动条的页面才存在，故需优先验证是否存在
    if (savedPosition) {
      // 存在后可以返回 savedPostion 再次跳转到该页面时，滚动条位置为离开该页面的位置
      return savedPosition
    } else {
      return {
        // 可以返回一个具有 top 属性的对象，当再次回到该页面时，会滚动到 top 位置
        top: 100
      }
    }
  },
  // 路由对象，即路径与组件间的对应关系以及相关信息
  routes
})

// 权限白名单：即不用权限即可访问的路径，用于导航守卫的过滤
// 白名单一般设置为登录界面，公开界面
const whiteList = ['/','/public']

// 导航守卫：即钩子函数(中间件)，在路由跳转时，会经历前置守卫，跳转，后置守卫
// 以上三个过程最终完成整个跳转行为

// 导航前置守卫用于拦截非权限的访问
// 参数为回调函数，回调函数参数为 to from 为目标和原路由的 Route 对象 next 为函数
// next() 放行 next(false) 阻拦 next(path:string) 阻拦并重定向
router.beforeEach((to,from,next)=>{
  // 在导航前置守卫中，一般验证是否具有 token 字段的权限或是否为白名单
  console.log('beforeEach')
  if(whiteList.includes(to.path) || localStorage.getItem('token')){
    // 验证成功则放行
    next()
  } else {
    // 不具备权限且访问权限路径，会拒绝访问并重定向回登录页
    next('/')
  }
})
// 导航后置守卫用于在跳转完成后实现特定功能，并不具备拦截作用
// 参数为回调函数，但不具有 next 拦截功能函数
router.afterEach((to,from)=>{
  console.log('afterEach')
  // 在跳转完成后，将页面的 title 设置为目标 title
  document.title = to.meta.title
})

// 默认导出 router 实例，作为路由插件在 main.ts 中挂载
export default router